<!--
 * @Author: wusd
 * @Date: 2022-05-18 14:58:44
 * @LastEditors: wusd
 * @LastEditTime: 2024-01-16 14:13:45
 * @Description: 
 * 
-->
<script lang="tsx">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
import { WTableConfig, WTableColumn, SearchParams, Pagination, WBtn, searchItem } from 'types/table'
import { AnyObj } from 'types/common'
import { CreateElement, VNode } from 'vue'
import { fixShowValue, mergeObject, resetObject, valueIsNull } from '@/untils/index'
import { renderFormElement } from '@/untils/renderFunction'
@Component({
  name: 'WSearch'
})
export default class WSearch extends Vue {
  @Prop({
    default: () => ({
      columns: []
    }),
    type: Object
  })
  tableConfig!: WTableConfig

  @Watch('tableConfig', { deep: true, immediate: true })
  changeConfig() {
    this.init()
  }

  public pageListKey = 'content'
  public isFirst = true
  /** 初始化页面 */
  public init() {
    this.setSearchBoxId()
    this.initTableConfig()
    this.$nextTick(() => {
      this.initSearchDivStyle()
    })
    this.isFirst = false
  }

  public resetIsFirst() {
    this.isFirst = true
  }
  public openBtnShow = true

  /**初始化参数 */
  public async initTableConfig() {
    /**合并配置项 */
    mergeObject(this.tableConfig, Vue.prototype?.$baseConfig?.tableConfig)
    this.tableConfig?.search?.list?.forEach(async item => {
      if (item.apiList) {
        let list = await item.apiList()
        item.list = list
        this.$forceUpdate()
      }
    })
    this.httpCodekey = Vue.prototype?.$baseConfig?.httpCodekey || this.httpCodekey
    if (valueIsNull(this.tableConfig.loading)) {
      this.tableConfig.loading = true
    }
    if (this.isFirst) {
      /** 初始化searchParams */
      this.initSearch()
    }
    if (this.tableConfig?.search?.stow === false) {
      this.searchStow = false
    }
    /** 初始化pagination */
    mergeObject(this.tableConfig?.pagination, this.pagination)
  }
  /** 初始化searchParams */
  initSearch() {
    let searchParams: AnyObj = {
      pageSize: this.tableConfig?.pagination?.pageSize || this.searchParams.pageSize,
      pageNum: this.tableConfig?.pagination?.pageNum || this.searchParams.pageNum
    }
    this.tableConfig?.search?.list?.forEach(item => {
      searchParams[item.prop] = valueIsNull(item.defaultValue) ? '' : item.defaultValue
    })
    this.searchParams = searchParams
  }
  /** 初始化搜索盒子样式 */
  initSearchDivStyle() {
    let searchBoxDom: any = document.getElementById(this.searchBoxId)
    if (!searchBoxDom) return
    let domMaxHeight = 0, //第一行元素最大高度
      bool = 0
    searchBoxDom.style['flex-wrap'] = 'wrap'
    let searchItemList = searchBoxDom.getElementsByClassName('w_search_item')
    let wSearchMaxHeight = 0
    for (let i = 0, j = searchItemList.length; i < j; i++) {
      let dom: any = searchItemList[i]
      if (bool < 1) {
        domMaxHeight = domMaxHeight > dom.offsetHeight ? dom.offsetHeight : dom.offsetHeight + 8
      }
      if (!dom.offsetLeft) {
        wSearchMaxHeight += dom.offsetHeight
        wSearchMaxHeight += 8
        bool++
      }
    }
    let minheight = this.tableConfig.search?.minHeight || domMaxHeight
    searchBoxDom.style.height = `${minheight}px`
    searchBoxDom.style.setProperty('--wSearchMaxHeight', `${this.tableConfig.search?.maxHeight || wSearchMaxHeight}px`)
    if (bool === 1 && valueIsNull(this.tableConfig.openBtnShow)) {
      this.openBtnShow = false
    }
  }

  public httpCodekey = 'code'

  /** 搜索条件默认 */
  public searchParams: SearchParams = {
    pageSize: 10,
    pageNum: 1
  }
  /** 是否收起所有搜索条件 */
  public searchStow = true
  /** pagination默认配置 */
  public pagination: Pagination = {
    show: true,
    align: 'right',
    pageSizes: [10, 20, 50, 100],
    layout: 'total, sizes, prev, pager, next, jumper'
  }
  /**
   * 渲染表单元素(搜索项|form表单项)
   */
  private renderSearchlement(
    h: CreateElement,
    params: {
      data: searchItem
    }
  ) {
    return renderFormElement(h, {
      config: params.data,
      model: this.searchParams,
      valueClass: 'w_search_item_value',
      parentConfig: {
        size: this.tableConfig?.search?.size
      }
    })
  }

  /** 渲染按钮 */
  private renderBtn(
    h: CreateElement,
    btn: WBtn,
    params: {
      column?: WTableColumn<AnyObj>
      row?: AnyObj
      index?: number
    } = {}
  ) {
    let { row } = params
    let disabled = this.fixDisabled(row, btn.disabled)
    let dom: VNode

    if (btn.render) {
      dom = btn.render(h, row)
    } else {
      dom = (
        <el-button
          class={`w_button_${btn.key}`}
          disabled={disabled}
          {...btn?.nodeData}
          size={btn.size}
          icon={btn.icon}
          onclick={() => this.handleBtn(btn, params)}
          type={btn.type}>
          {btn.text}
        </el-button>
      )
    }
    return dom
  }
  /** 点击按钮 */
  private handleBtn(
    btn: WBtn,
    params: {
      column?: WTableColumn<AnyObj>
      row?: AnyObj
      index?: number
    }
  ) {
    /** 如果存在回调函数，则只调用回调 */
    if (btn?.callback) {
      btn.callback(params)
      return
    }
  }

  private async handleSearch(type = 'search') {
    this.searchParams.pageNum = 1
    if (type === 'reset') {
      this.searchParams = resetObject(this.searchParams)
    }
    if (this.tableConfig?.search?.searchBtn?.callback) {
      this.loading = true
      this.tableConfig?.search?.searchBtn?.callback(this.searchParams)
      this.loading = false
    }
  }

  loading = false

  private fixDisabled(row: any, disabled: any) {
    if (typeof disabled === 'boolean') {
      return disabled
    }
    if (!disabled) {
      return false
    } else {
      return disabled(row)
    }
  }
  searchBoxId = ''
  public setSearchBoxId() {
    this.searchBoxId = `w_search_box_${Math.random()}`
  }

  protected render(h: CreateElement) {
    return (
      <div class="w_table">
        {this.tableConfig?.search?.list?.length && (
          <div id={this.searchBoxId} class={['w_search', this.searchStow ? 'w_search_hidden' : 'w_search_show']}>
            {this.tableConfig?.search?.list?.map(item => {
              return (
                fixShowValue({}, item.show) && (
                  <div
                    class={['w_search_item', 'search_item_' + item.prop]}
                    style={{
                      width: item.span
                        ? (100 * item.span) / 24 + '%'
                        : 100 / (this.tableConfig?.search?.rowNum || 4) + '%'
                    }}
                    {...item?.nodeData}>
                    <span
                      class="w_search_item_label"
                      style={{ width: item?.labelWidth || this.tableConfig?.search?.labelWidth || '80px' }}>
                      {item.label}
                    </span>
                    {this.renderSearchlement(h, { data: item })}
                  </div>
                )
              )
            })}
          </div>
        )}
        <div class="w_outBox">
          <div class="w_outBtns">
            {this.tableConfig.outBtns
              ?.filter(item => {
                return fixShowValue({}, item.show)
              })
              ?.map(item => {
                item.size = item.size || 'small'
                return this.renderBtn(h, item)
              })}
          </div>
          {this.tableConfig?.search?.list?.length && (
            <div class="w_searchBtns">
              {this.tableConfig.rightBtns
                ?.filter(item => {
                  return fixShowValue({}, item.show)
                })
                ?.map(item => {
                  item.size = item.size || 'small'
                  return this.renderBtn(h, item)
                })}
              {this.tableConfig?.search?.searchBtn?.show !== false && (
                <el-button
                  type="primary"
                  size="small"
                  {...this.tableConfig?.search?.searchBtn?.nodeData}
                  onclick={this.handleSearch}>
                  {this.tableConfig?.search?.searchBtn?.text || '查询'}
                </el-button>
              )}
              {this.tableConfig?.resetBtnShow && (
                <el-button type="primary" size="small" onclick={() => this.handleSearch('reset')}>
                  重置
                </el-button>
              )}
              {this.tableConfig?.openBtnShow !== false && this.openBtnShow && (
                <el-button
                  type="primary"
                  class="w_table_openbtn"
                  size="small"
                  onclick={() => (this.searchStow = !this.searchStow)}>
                  {this.searchStow ? '展开' : '收起'}查询条件
                  <i class={this.searchStow ? 'el-icon-arrow-down' : 'el-icon-arrow-up'}></i>
                </el-button>
              )}
            </div>
          )}
        </div>
      </div>
    )
  }
}
</script>

<style lang="scss" scoped>
//--wSearchHeight为变量,必须以--开头，否则其它页面使用这个变量不会生效
$wSearchMaxHeight: var(--wSearchMaxHeight, 0px);

.w_table {
  .w_search {
    width: 100%;
    display: flex;
    overflow: hidden;
    transition: all 0.5s;
    position: relative;
    .w_search_item {
      display: flex;
      flex-shrink: 0;
      align-items: center;
      margin-bottom: 8px;
      overflow: hidden;
      .w_search_item_label {
        font-size: 14px;
        margin-right: 8px;
        flex-shrink: 0;
        letter-spacing: 4px;
        text-align: center;
        color: #333;
      }
      .w_search_item_value {
        flex: 1;
      }
    }
  }
  .w_search_show {
    height: $wSearchMaxHeight !important;
  }
  .w_outBox {
    width: 100%;
    display: flex;
    margin-bottom: 16px;
    .w_searchBtns {
      display: flex;
      flex-grow: 1;
      justify-content: flex-end;
    }
  }
  .w_pagination {
    margin-top: 16px;
  }
}
</style>
